/*
 * @(#) XmlUtils
 * 版权声明 厦门畅享信息技术有限公司, 版权所有 违者必究
 *
 * <br> Copyright:  Copyright (c) 2018
 * <br> Company:厦门畅享信息技术有限公司
 * <br> @author cjh
 * <br> 2018-07-11 21:36:00
 * <br> @version 1.0
 * ————————————————————————————————
 *     修改记录
 *     修改者：
 *     修改时间：
 *     修改原因：
 * ————————————————————————————————
 */


package com.sunsharing.utils;

import lombok.extern.log4j.Log4j;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.tree.DefaultAttribute;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * xml解析工具
 */
@Log4j
public class XmlUtil {

    /**
     * 获取xml树对象
     *
     * @param path xml文件路径
     * @return xml节点对象
     */
    public Element getXmlElement(String path) {
        Element root = null;
        try {
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(new File(path));
            root = document.getRootElement();
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return root;
    }

    /**
     * 获取对象的set方法
     *
     * @param objectClass class对象
     * @param fieldName 要获取的set方法的变量名
     * @return class对象的fieldName的set方法
     */
    public Method getSetMethod(Class objectClass, String fieldName) {
        try {
            Class[] parameterTypes = new Class[1];
            Field[] fields = objectClass.getDeclaredFields();
            for (Field f : fields) {
                if (f.getName().equals(fieldName)) {
                    parameterTypes[0] = f.getType();
                    StringBuffer sb = new StringBuffer();
                    sb.append("set");
                    sb.append(fieldName.substring(0, 1).toUpperCase());
                    sb.append(fieldName.substring(1));
                    Method method = objectClass.getMethod(sb.toString(), parameterTypes);
                    return method;
                }
            }
            log.info("找不【" + fieldName + "】到对应的set方法");
            return null;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解析成xml对象
     *
     * @param node  对象节点
     * @param clazz 反射的类
     * @param isList 是否是列表
     * @return 解析后的clazz对象
     */
    public <T> T parse2Object(Element node, Class<T> clazz, boolean isList)
            throws InstantiationException, NoSuchFieldException, InvocationTargetException, IllegalAccessException {
        T instance = clazz.newInstance();
        List dataList = new ArrayList();
        List<Element> childNode = null;
        String listGeneric = "";//列表泛型对象名称
        try {
            childNode = node.elements();
            if (childNode.size() == 0) {
                return (T) node.getTextTrim();
            }
            for (Element ele : childNode) {
                Object obj = null;
                Method method = null;
                log.info("===" + ele.getName());
                if (isList) {
                    obj = parse2Object(ele, clazz, false);
                    instance = parseAttributes(clazz, obj, ele);
                    dataList.add(instance);
                    continue;
                }
                Class nextClazz = clazz.getDeclaredField(ele.getName()).getType();//获取变量对象的Class
                //List接口类型
                if (nextClazz.isInterface()) {
                    listGeneric = interfaceGeneric2String(clazz, ele.getName());
                    obj = parse2Object(ele, Class.forName(listGeneric), true);
                    method = getSetMethod(clazz, ele.getName());
                } else {
                    //非接口类型
                    obj = parse2Object(ele, nextClazz, false);
                    method = getSetMethod(clazz, ele.getName());
                }
                obj = parseAttributes(clazz,obj,ele);
                if (method != null) {
                    method.invoke(instance, new Object[]{obj});
                }
            }
        } catch (ClassNotFoundException e) {
            log.info("未找到【" + listGeneric + "】对象");
            log.info("错误报告：" + e.getMessage());
            e.printStackTrace();
        }
        if (isList) {
            return (T) dataList;
        }
        return instance;
    }

    /**
     * 解析xml成指定对象
     *
     * @param path  xml文件路径
     * @param clazz 反射类
     */
    public <T> T parse2Object(String path, Class<T> clazz)
            throws
            InvocationTargetException,
            NoSuchFieldException,
            InstantiationException,
            IllegalAccessException, ClassNotFoundException {
        Element root = getXmlElement(path);
        return parse2Object(root, clazz, false);
    }

    /**
     * 解析节点属性值
     * @param clazz 对象类型
     * @param obj 实例对象
     * @param node xml节点
     */
    public <T> T parseAttributes(Class<T> clazz, Object obj, Element node)
            throws IllegalAccessException, InstantiationException, InvocationTargetException {
        T instance = clazz.newInstance();
        Method method = null;
        instance = (T) obj;
        List<DefaultAttribute> attributes = node.attributes();
        for (DefaultAttribute attr : attributes) {
            method = getSetMethod(clazz, attr.getName());
            if (method != null) {
                method.invoke(instance, attr.getText());
            }
        }
        return instance;
    }

    /**
     * 从list接口中获取泛型对象的名称
     *
     * @param clazz 泛型对象
     * @param fieldName 要获取的list成员变量的名称
     * @return list对象的泛型对象的class路径
     */
    public String interfaceGeneric2String(Class clazz, String fieldName) throws NoSuchFieldException {
        String objName = clazz.getDeclaredField(fieldName).getGenericType().getTypeName();
        int start = objName.indexOf('<');
        int end = objName.indexOf('>');
        return objName.substring(start + 1, end);
    }




}